/*
 -- IOTA Crypto Core
 --
 -- 2018 by Thomas Pototschnig <microengineer18@gmail.com>
 -- discord: pmaxuw#8292
 -- https://gitlab.com/iccfpga-rv
 --
 -- Permission is hereby granted, free of charge, to any person obtaining
 -- a copy of this software and associated documentation files (the
 -- "Software"), to deal in the Software without restriction, including
 -- without limitation the rights to use, copy, modify, merge, publish,
 -- distribute, sublicense, and/or sell copies of the Software, and to
 -- permit persons to whom the Software is furnished to do so, subject to
 -- the following conditions:
 --
 -- The above copyright notice and this permission notice shall be
 -- included in all copies or substantial portions of the Software.
 --
 -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 -- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 -- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 -- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 -- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 -- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 -- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWAR
 */
#ifndef SECURE_H_
#define SECURE_H_

#include "main.h"
#include "atca_command.h"
#include <string.h>

extern "C" {
#include "bip32.h"
#include "bip39.h"

#include "secp256k1.h"
#include "slip39.h"
}


// use slot 7 for ledger-compatible seed
#define BIP39_SLOT		7

// seed-class for easier implementation of seed caching
class SecureSeed {
private:
	int m_slot;
	int m_security;
	char m_cacheChars[81];
	uint8_t m_cacheBytes[48];
	bool m_cacheSeed;
	bool m_validSeed;

	uint32_t crc32(uint8_t *data, size_t length, uint32_t previousCrc32 = 0);

	bool write(uint8_t seedBytes[48]);
	void clear();
public:
	SecureSeed(int slot) {
		m_slot = slot;
		m_security = 2;
		initEmpty();
	}
	virtual ~SecureSeed() {
		release();
	}

	void initEmpty() {
		m_validSeed = false;
		memset(m_cacheChars, 0, sizeof(m_cacheChars));
		memset(m_cacheBytes, 0, sizeof(m_cacheBytes));
		m_cacheSeed = true; /* default: saves over a second */
	}

	char* getSeedChars() {
		return m_cacheChars;
	}
	uint8_t* getSeedBytes() {
		return m_cacheBytes;
	}

	bool load();
	bool writeRandomSeed();
	void setCached(bool flag) {
		m_cacheSeed = flag;
	}
	void setValid(bool flag) {
		m_validSeed = flag;
	}

	void release();	// releases deletes key from memory if not cachable
	bool isValid() {
		return m_validSeed;
	}
	bool isCached() {
		return m_cacheSeed;
	}

	// compatibility to ledger nano implementation
	void setSecurity(int i) {
		m_security = i;
	}
	int getSecurity() {
		return m_security;
	}

};

// bip39 variant
class SecureSeedBIP39: public SecureSeed {
private:
	uint32_t m_path[4];
	Keccak384FPGA m_keccak;
	HDNode m_node;
public:
	SecureSeedBIP39(int slot) : SecureSeed(slot) {
		memset(m_path, 0, sizeof(m_path));
	}
	virtual ~SecureSeedBIP39() {
		SecureSeed::release();
	}

	bool loadBIP39(uint32_t bip39Path[4]);
};

// a simply class that ensures that seed->release is executed when
// returning from a privileged function
// release knows by itself if the seed really is to release or not
// (eg if caching in RAM is enabled or it's a bip39 seed)
class SeedWatch {
private:
	SecureSeed* m_seed;
public:
	SeedWatch(SecureSeed* seed) {
		this->m_seed = seed;
	}
	~SeedWatch() {
		m_seed->release();
	}

};

namespace Secure {
bool init();
const uint8_t* getApiKey();
bool initSecureElement(uint8_t slot4_cmp_key[32]);
bool isInitialized();
bool isConfigLocked(uint8_t zone = LOCK_ZONE_CONFIG);
bool generateRandomSeedBytes(uint8_t seedBytes[48]);

}
;

extern SecureSeed *seeds[8];

#endif /* SECURE_H_ */
